package xyz.scootaloo.server.mini

import io.vertx.config.ConfigRetriever
import io.vertx.core.AbstractVerticle
import io.vertx.core.Future
import io.vertx.core.Promise
import io.vertx.core.Vertx
import io.vertx.core.http.HttpServer
import io.vertx.core.json.JsonObject
import io.vertx.ext.web.Router
import io.vertx.ext.web.handler.StaticHandler
import io.vertx.kotlin.config.configRetrieverOptionsOf
import io.vertx.kotlin.config.configStoreOptionsOf
import io.vertx.kotlin.core.json.jsonObjectOf

/**
 * @author flutterdash@qq.com
 * @since 2022/1/19 13:54
 */

class MiniServer : AbstractVerticle() {

    private val configPath = "config.json"

    private var port = 8080
    private var home = "./home"

    override fun start(startPromise: Promise<Void>) {
        vertx.fileSystem().exists(configPath)
            .onSuccess {
                readConfig().onComplete { ar ->
                    if (ar.succeeded()) {
                        port = ar.result().safeGetInt("port", 8080)
                        home = ar.result().safeGetString("home", "./home")
                    }

                    runServer()
                        .onSuccess {
                            println("服务启动成功, 监听端口: $port")
                            startPromise.complete()
                        }
                        .onFailure {
                            println("服务启动失败, ${it.message}")
                            startPromise.fail(it)
                        }
                }
            }
            .onFailure {
                println("未读取到配置文件, 缺少关键信息, 服务无法启动")
                startPromise.fail("未在指定路径读取到配置")
            }
    }

    private fun readConfig(): Future<JsonObject> {
        return ConfigRetriever.create(
            vertx, configRetrieverOptionsOf()
                .addStore(
                    configStoreOptionsOf()
                        .setType("file")
                        .setFormat("json")
                        .setConfig(
                            jsonObjectOf(
                                "path" to configPath
                            )
                        )
                )
        ).config
    }

    private fun runServer(): Future<HttpServer> {
        val server = vertx.createHttpServer()
        val router = Router.router(vertx)
        router.route("/static/*").handler(StaticHandler.create(home))
        server.requestHandler(router)
        return server.listen(port)
    }

    private fun JsonObject.safeGetInt(key: String, def: Int): Int = getOrDef(key, ::getInteger, def)
    private fun JsonObject.safeGetString(key: String, def: String): String = getOrDef(key, ::getString, def)

    private fun <In, Out> getOrDef(key: In, block: (In) -> Out, def: Out): Out = try {
        block(key) ?: def
    } catch (ignore: Throwable) {
        def
    }
}

fun main() {
    Vertx.vertx().deployVerticle(MiniServer())
}